package com.letu.log;


import com.alibaba.fastjson.JSONObject;
import com.letu.annotation.log.entity.OptLogDTO;
import com.letu.cache.redis.RedisOps;
import com.letu.core.context.ContextConstants;
import com.letu.core.context.ContextUtil;
import com.letu.core.context.StaticContextUtil;
import com.letu.core.jackson.JsonUtil;
import com.letu.core.plumelog.BaseLogMessage;
import com.letu.core.plumelog.CompressMessage;
import com.letu.core.point.OrderBusinBasePoint;
import com.letu.log.aspect.SysLogAspect;
import com.letu.log.event.SysLogListener;
import com.letu.log.monitor.PointUtil;
import com.letu.log.point.*;
import com.letu.log.properties.OptLogProperties;
import com.letu.plumelog.constant.LogMessageConstant;
import com.letu.plumelog.handler.MessageAppenderFactory;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;

import java.io.UnsupportedEncodingException;

/**
 * 日志自动配置
 * <p>
 * 启动条件：
 * 1，存在web环境
 * 2，配置文件中lamp.log.enabled=true 或者 配置文件中不存在：lamp.log.enabled 值
 *
 * @author ligang
 * @date 2021/08/4
 */
@Slf4j
@EnableAsync
@Configuration
@AllArgsConstructor
@ConditionalOnWebApplication
@ConditionalOnProperty(prefix = OptLogProperties.PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)
public class LogAutoConfiguration {

//    @Autowired
//    private KafkaTemplate<String, Object> kafkaTemplate;


    //    @Autowired
//    private LogPointProducer logPointProducer;
//
//
//    @Autowired
//    private BusinessPointProducer businessPointProducer;
//
//    @Autowired
//    private DataPointProducer dataPointProducer;
//
//    @Autowired
//    private OrderBusinPointProducer orderBusinPointProducer;
//
//    @Autowired
//    private MessagePointProducer messagePointProducer;
//
//    @Autowired
//    private BroadPointProducer broadPointProducer;


    @Autowired
    RedisOps redisOps;

    @Bean
    @ConditionalOnMissingBean
    public SysLogAspect sysLogAspect() {
        return new SysLogAspect();
    }

//    @Autowired
//    private KafkaNameConfig kafkaNameConfig;
//    @Value("${ef.kafka.point}")
//    private String pointKafkaName;
//
//    @Value("${ef.kafka.datasync}")
//    private String dataSyncKafkaName;

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnExpression("${lamp.log.enabled:true} && 'LOGGER'.equals('${lamp.log.type:LOGGER}')")
    public SysLogListener sysLogListener() {


        // TODO: 2021/8/6 在这里处理接口日志功能 OptLogDTO
        return new SysLogListener(log -> {
            //记录MDC的行为日志
            //用户id
            MDC.put(ContextConstants.JWT_KEY_USER_ID, log.getUserId() + "");
            //用户姓名
            MDC.put(ContextConstants.JWT_KEY_NAME, log.getUserName());
            //链路id
            MDC.put(ContextConstants.LOG_TRACE_ID, log.getTraceId());
            //ip地址
            MDC.put(ContextConstants.IP_HEADER, log.getIpAddr());
            //埋点类型
            MDC.put(ContextConstants.POINT_TYPE, PointEnum.SYSLOG.getCode());

//            PointUtil.debug(log.getTraceId(), PointEnum.SYSLOG.getCode(), JsonUtil.toJson(log));
            //放入mq
            MessageAppenderFactory.pushSystemLogQueue(log);
        });
    }

    /**
     * 埋点日志处理
     *
     * @return
     */
//    @Bean
//    @ConditionalOnMissingBean
//    @ConditionalOnExpression("${lamp.log.enabled:true} && 'LOGGER'.equals('${lamp.log.type:LOGGER}')")
//    public PointLogListener pointLogListener() {
//        // TODO: 2021/8/6 在这里处理埋点日志功能 PointEvent
//        // TODO: 2022/1/21 埋点处理
//        //目前只是打印，待存储方案确定，可以存入到kafaka
//        return new PointLogListener(log -> {
//            //打印在控制台（正式环境，可注释这行代码）
////            PointUtil.info("0", "POINTLOG", JsonUtil.toJson(log));
//            //记录到日志
//            PointUtil.debug("0", "POINTLOG", JsonUtil.toJson(log));
//            //推送到kafaka
////            try{
////                kafkaTemplate.send(kafkaNameConfig.getPointKafkaName(),JsonUtil.toJson(log));
////            }catch (Exception e){
////                //说明kafaka没有，则不推送
////            }
//            //推送到rocket mq
//            Message msg = null;// body
//            try {
//
//                msg = new Message("log_dev", // topic
//                        "11", // tag
//                        "OrderID11112", // key
//                        JSONObject.toJSONString(log).getBytes(RemotingHelper.DEFAULT_CHARSET));
//                logPointProducer.send(msg);
//            } catch (UnsupportedEncodingException e) {
//                e.printStackTrace();
//            }
//
//
//        });
//    }


    /**
     * 业务埋点日志处理
     *
     * @return
     */
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnExpression("${lamp.log.enabled:true} && 'LOGGER'.equals('${lamp.log.type:LOGGER}')")
    public BusinPointLogListener businPointLogListener() {
        // TODO: 2021/8/6 在这里处理埋点日志功能 PointEvent
        // TODO: 2022/1/21 埋点处理
        //目前只是打印，待存储方案确定，可以存入到kafaka
        return new BusinPointLogListener(log -> {
            //记录MDC的行为日志
            //用户id
            MDC.put(ContextConstants.JWT_KEY_USER_ID, log.getUserId() + "");
            //用户姓名
            MDC.put(ContextConstants.JWT_KEY_NAME, log.getUserName());
            //链路id
            MDC.put(ContextConstants.LOG_TRACE_ID, log.getTrace());
            //ip地址
            MDC.put(ContextConstants.IP_HEADER, log.getIpAddr());
            //埋点类型
            MDC.put(ContextConstants.POINT_TYPE, PointEnum.POINTBUSINESSLOG.getCode());

            //打印在控制台（正式环境，可注释这行代码）
//            PointUtil.info("0", "POINTLOG", JsonUtil.toJson(log));
            //记录到日志
            PointUtil.debug(log.getTrace(), PointEnum.POINTBUSINESSLOG.getCode(), JsonUtil.toJson(log));
            //推送到kafaka
//            try {
//                kafkaTemplate.send(kafkaNameConfig.getBusinPointKafkaName(), JsonUtil.toJson(log));
//            } catch (Exception e) {
//                //说明kafaka没有，则不推送
//            }
            //推送到rocket mq
//            businessPointProducer.send(log);
        });
    }


    /**
     * 日志埋点处理
     *
     * @return
     */
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnExpression("${lamp.log.enabled:true} && 'LOGGER'.equals('${lamp.log.type:LOGGER}')")
    public LogPointLogListener logPointLogListener() {
        // TODO: 2021/8/6 在这里处理埋点日志功能 PointEvent
        // TODO: 2022/1/21 埋点处理
        //目前只是打印，待存储方案确定，可以存入到kafaka
        return new LogPointLogListener(log -> {
            //记录MDC的行为日志
            //用户id
            MDC.put(ContextConstants.JWT_KEY_USER_ID, log.getUserId() + "");
            //用户姓名
            MDC.put(ContextConstants.JWT_KEY_NAME, log.getUserName());
            //链路id
            MDC.put(ContextConstants.LOG_TRACE_ID, log.getTrace());
            //ip地址
            MDC.put(ContextConstants.IP_HEADER, log.getIpAddr());
            //埋点类型
            MDC.put(ContextConstants.POINT_TYPE, PointEnum.POINTLOG.getCode());
            //打印在控制台（正式环境，可注释这行代码）
//            PointUtil.info("0", "POINTLOG", JsonUtil.toJson(log));
            //记录到日志
            PointUtil.debug(log.getTrace(), PointEnum.POINTLOG.getCode(), JsonUtil.toJson(log));
            //推送到rocket mq
//            logPointProducer.send(log);
        });
    }


    /**
     * 数据埋点处理
     *
     * @return
     */
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnExpression("${lamp.log.enabled:true} && 'LOGGER'.equals('${lamp.log.type:LOGGER}')")
    public DataPointLogListener dataPointLogListener() {
        // TODO: 2021/8/6 在这里处理埋点日志功能 PointEvent
        // TODO: 2022/1/21 埋点处理
        //目前只是打印，待存储方案确定，可以存入到kafaka
        return new DataPointLogListener(log -> {
            //记录MDC的行为日志
            //用户id
            MDC.put(ContextConstants.JWT_KEY_USER_ID, log.getUserId() + "");
            //用户姓名
            MDC.put(ContextConstants.JWT_KEY_NAME, log.getUserName());
            //链路id
            MDC.put(ContextConstants.LOG_TRACE_ID, log.getTrace());
            //ip地址
            MDC.put(ContextConstants.IP_HEADER, log.getIpAddr());
            //埋点类型
            MDC.put(ContextConstants.POINT_TYPE, PointEnum.POINTDATALOG.getCode());
            //打印在控制台（正式环境，可注释这行代码）
//            PointUtil.info("0", "POINTLOG", JsonUtil.toJson(log));
            //记录到日志
            PointUtil.debug(log.getTrace(), PointEnum.POINTDATALOG.getCode(), JsonUtil.toJson(log));
            //推送到rocket mq
//            dataPointProducer.send(log);
        });
    }


    /**
     * 多个功能串联处理
     *
     * @return
     */
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnExpression("${lamp.log.enabled:true} && 'LOGGER'.equals('${lamp.log.type:LOGGER}')")
    public OrderBusinPointLogListener orderBusinPointLogListener() {
        // TODO: 2021/8/6 在这里处理埋点日志功能 PointEvent
        // TODO: 2022/1/21 埋点处理
        //目前只是打印，待存储方案确定，可以存入到kafaka
        return new OrderBusinPointLogListener(log -> {
            //记录MDC的行为日志
            //用户id
            MDC.put(ContextConstants.JWT_KEY_USER_ID, log.getUserId() + "");
            //用户姓名
            MDC.put(ContextConstants.JWT_KEY_NAME, log.getUserName());
            //链路id
            MDC.put(ContextConstants.LOG_TRACE_ID, log.getTrace());
            //ip地址
            MDC.put(ContextConstants.IP_HEADER, log.getIpAddr());
            //埋点类型
            MDC.put(ContextConstants.POINT_TYPE, PointEnum.POINTORDERBUSINESSLOG.getCode());
            //打印在控制台（正式环境，可注释这行代码）
//            PointUtil.info("0", "POINTLOG", JsonUtil.toJson(log));
            //记录到日志
            PointUtil.debug(log.getTrace(), PointEnum.POINTORDERBUSINESSLOG.getCode(), JsonUtil.toJson(log));
            //推送到rocket mq
//            orderBusinPointProducer.send(log);
        });
    }


    /**
     * 消息中心处理
     *
     * @return
     */
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnExpression("${lamp.log.enabled:true} && 'LOGGER'.equals('${lamp.log.type:LOGGER}')")
    public MessagePointLogListener messagePointLogListener() {
        // TODO: 2021/8/6 在这里处理埋点日志功能 PointEvent
        // TODO: 2022/1/21 埋点处理
        //目前只是打印，待存储方案确定，可以存入到kafaka
        return new MessagePointLogListener(log -> {
            //记录MDC的行为日志
            //用户id
            MDC.put(ContextConstants.JWT_KEY_USER_ID, log.getUserId() + "");
            //用户姓名
            MDC.put(ContextConstants.JWT_KEY_NAME, log.getUserName());
            //链路id
            MDC.put(ContextConstants.LOG_TRACE_ID, log.getTrace());
            //ip地址
            MDC.put(ContextConstants.IP_HEADER, log.getIpAddr());
            //埋点类型
            MDC.put(ContextConstants.POINT_TYPE, PointEnum.POINTMESSAGELOG.getCode());
            //打印在控制台（正式环境，可注释这行代码）
//            PointUtil.info("0", "POINTLOG", JsonUtil.toJson(log));
            //记录到日志
            PointUtil.debug(log.getTrace(), PointEnum.POINTMESSAGELOG.getCode(), JsonUtil.toJson(log));
            //推送到rocket mq
//            messagePointProducer.send(log);
        });
    }


    /**
     * 广播处理
     *
     * @return
     */
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnExpression("${lamp.log.enabled:true} && 'LOGGER'.equals('${lamp.log.type:LOGGER}')")
    public BroadPointLogListener broadPointLogListener() {
        // TODO: 2021/8/6 在这里处理埋点日志功能 PointEvent
        // TODO: 2022/1/21 埋点处理
        //目前只是打印，待存储方案确定，可以存入到kafaka
        return new BroadPointLogListener(log -> {
            //记录MDC的行为日志
            //用户id
            MDC.put(ContextConstants.JWT_KEY_USER_ID, log.getUserId() + "");
            //用户姓名
            MDC.put(ContextConstants.JWT_KEY_NAME, log.getUserName());
            //链路id
            MDC.put(ContextConstants.LOG_TRACE_ID, log.getTrace());
            //ip地址
            MDC.put(ContextConstants.IP_HEADER, log.getIpAddr());
            //埋点类型
            MDC.put(ContextConstants.POINT_TYPE, PointEnum.POINTBROADLOG.getCode());
            //打印在控制台（正式环境，可注释这行代码）
//            PointUtil.info("0", "POINTLOG", JsonUtil.toJson(log));
            //记录到日志
            PointUtil.debug(log.getTrace(), PointEnum.POINTBROADLOG.getCode(), JsonUtil.toJson(log));
            //推送到rocket mq
//            broadPointProducer.send(log);
        });
    }

    /**
     * 事务日志处理
     *
     * @return
     */
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnExpression("${lamp.log.enabled:true} && 'LOGGER'.equals('${lamp.log.type:LOGGER}')")
    public TransactionLogListener transactionLogListener() {
        return new TransactionLogListener(log -> {
            //记录MDC的行为日志
            //用户id
            MDC.put(ContextConstants.JWT_KEY_USER_ID, log.getUserId() + "");
            //用户姓名
            MDC.put(ContextConstants.JWT_KEY_NAME, log.getUserName());
            //链路id
            MDC.put(ContextConstants.LOG_TRACE_ID, log.getTrace());
            //ip地址
            MDC.put(ContextConstants.IP_HEADER, log.getIpAddr());
            //埋点类型
            MDC.put(ContextConstants.POINT_TYPE, PointEnum.TRANSACTIONLOG.getCode());
            //记录到日志
            PointUtil.debug(log.getTrace(), PointEnum.TRANSACTIONLOG.getCode(), log.toString());
        });
    }


    /**
     * 日志埋点处理
     *
     * @return
     */
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnExpression("${lamp.log.enabled:true} && 'LOGGER'.equals('${lamp.log.type:LOGGER}')")
    public AllLogPointLogListener allLogPointLogListener() {
        return new AllLogPointLogListener(log -> {
//            PointUtil.info("0", "POINTLOG", JsonUtil.toJson(log));
            BaseLogMessage logMessage = log.getLogMessage();
//            redisOps.send(LogMessageConstant.REDIS_ALL_LOG_KEY, compressMessage);
            //放入mq
            MessageAppenderFactory.pushRundataQueue(logMessage);
        });
    }
}
